package cn.wolfcode.business.service.impl;

import cn.wolfcode.business.domain.BusBpmnInfo;
import cn.wolfcode.business.domain.BusCarPackageAudit;
import cn.wolfcode.business.domain.BusServiceItem;
import cn.wolfcode.business.mapper.BusCarPackageAuditMapper;
import cn.wolfcode.business.service.IBusBpmnInfoService;
import cn.wolfcode.business.service.IBusCarPackageAuditService;
import cn.wolfcode.business.service.IBusServiceItemService;
import cn.wolfcode.business.vo.AuditVO;
import cn.wolfcode.business.vo.HistoryVO;
import cn.wolfcode.common.core.domain.entity.SysUser;
import cn.wolfcode.common.utils.DateUtils;
import cn.wolfcode.common.utils.PageUtils;
import cn.wolfcode.common.utils.SecurityUtils;
import cn.wolfcode.system.service.ISysUserService;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 套餐审核Service业务层处理
 * 
 * @author wolfcode
 * @date 2025-05-09
 */
@Service
public class BusCarPackageAuditServiceImpl implements IBusCarPackageAuditService 
{
    @Autowired
    private BusCarPackageAuditMapper busCarPackageAuditMapper;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private IBusServiceItemService serviceItemService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private IBusBpmnInfoService busBpmnInfoService;
    @Autowired
    private ISysUserService userService;

    /**
     * 查询套餐审核
     * 
     * @param id 套餐审核主键
     * @return 套餐审核
     */
    @Override
    public BusCarPackageAudit selectBusCarPackageAuditById(Long id)
    {
        return busCarPackageAuditMapper.selectBusCarPackageAuditById(id);
    }

    /**
     * 查询套餐审核列表
     * 
     * @param busCarPackageAudit 套餐审核
     * @return 套餐审核
     */
    @Override
    public List<BusCarPackageAudit> selectBusCarPackageAuditList(BusCarPackageAudit busCarPackageAudit)
    {
        return busCarPackageAuditMapper.selectBusCarPackageAuditList(busCarPackageAudit);
    }

    /**
     * 新增套餐审核
     * 
     * @param busCarPackageAudit 套餐审核
     * @return 结果
     */
    @Override
    public int insertBusCarPackageAudit(BusCarPackageAudit busCarPackageAudit)
    {
        busCarPackageAudit.setCreateTime(DateUtils.getNowDate());
        return busCarPackageAuditMapper.insertBusCarPackageAudit(busCarPackageAudit);
    }

    /**
     * 修改套餐审核
     * 
     * @param busCarPackageAudit 套餐审核
     * @return 结果
     */
    @Override
    public int updateBusCarPackageAudit(BusCarPackageAudit busCarPackageAudit)
    {
        return busCarPackageAuditMapper.updateBusCarPackageAudit(busCarPackageAudit);
    }

    /**
     * 批量删除套餐审核
     * 
     * @param ids 需要删除的套餐审核主键
     * @return 结果
     */
    @Override
    public int deleteBusCarPackageAuditByIds(Long[] ids)
    {
        return busCarPackageAuditMapper.deleteBusCarPackageAuditByIds(ids);
    }

    /**
     * 删除套餐审核信息
     * 
     * @param id 套餐审核主键
     * @return 结果
     */
    @Override
    public int deleteBusCarPackageAuditById(Long id)
    {
        return busCarPackageAuditMapper.deleteBusCarPackageAuditById(id);
    }

    /**
     * 流程图查看
     */
    @Override
    @Transactional
    public InputStream getProcessImg(Long instanceId) {
        // 参数合理化验证
        if (instanceId == null) {
            throw new RuntimeException("非法参数");
        }

        // 创建插件 绘制流程图
        DefaultProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
        // 通过传递的参数流程实例 id 查询流程实例对象
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(instanceId.toString())
                .singleResult();
        // 活动节点集合
        List<String> activeActivityIds = null;
        BpmnModel bpmnModel = null;
        if(processInstance == null){
            // 若当前流程实例已经被撤销。那么将成为历史。我们可以去历史中获取该流程实例。
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(instanceId.toString())
                    .singleResult();
            String processDefinitionId = historicProcessInstance.getProcessDefinitionId();
            // 根据流程定义来获取 BpmnModel 对象。
            bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
            activeActivityIds = Collections.emptyList();
        } else {
            // 根据流程实例对象来获取流程定义 id
            String processDefinitionId = processInstance.getProcessDefinitionId();
            // 根据流程定义来获取 BpmnModel 对象。
            bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
            // 获取到当前活动的节点。
            activeActivityIds = runtimeService.getActiveActivityIds(instanceId.toString());
        }
        // 绘制流程图
        /**
         * 第一个参数：模型对象（当前流程都有那些节点，哪些连线，哪些坐标 等等...）
         * 第二个参数：需要高亮的节点。
         * 第三个参数：需要高亮的连线。
         * 第 4 5 6 个参数：生成图后展示的字体。
         */
        InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel,
                activeActivityIds,
                Collections.emptyList(),
                "宋体",
                "宋体",
                "宋体");
        return inputStream;
    }

    /**
     * 流程撤销
     */
    @Override
    @Transactional
    public int processCancel(Long id) {
        if (id == null) {
            throw new RuntimeException("非法参数");
        }
        // 查询出对应的套餐审核对象。
        BusCarPackageAudit carPackageAudit = this.selectBusCarPackageAuditById(id);
        if(carPackageAudit == null){
            throw new RuntimeException("非法参数");
        }
        // 验证状态审核状态必须是审核中才可以进行撤销操作。
        if(!(BusCarPackageAudit.STATUS_IN_PROGRESS.equals(carPackageAudit.getStatus()))){
            throw new RuntimeException("处于审核中的流程才可以进行撤销操作");
        }
        // 将当前这个套餐对象的审核状态修改为 -->  审核撤销。
        busCarPackageAuditMapper.changeStatusById(id,BusCarPackageAudit.STATUS_CANCEL);
        // 删除对应的流程实例。
        runtimeService.deleteProcessInstance(carPackageAudit.getInstanceId(),"流程撤销");
        // 根据套餐审核对象找到服务项的 id。根据 id 在将服务项的状态修改为初始化。
        return serviceItemService.changeAuditStatusById(carPackageAudit.getServiceItemId(), BusServiceItem.AUDITSTATUS_INIT);
    }

    /**
     * 查看历史审批列表信息
     */
    @Override
    public List<HistoryVO> getHistoryTaskList(Long instanceId) {
        // 参数合理化验证
        if (instanceId == null) {
            throw new RuntimeException("非法参数");
        }
        // 根据流程实例 Id 来查询历史任务集合
        List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(instanceId.toString())
                .list();
        // 遍历该集合
        /*List<HistoryVO> historyVOList = historicTaskInstanceList.stream().map(task -> {
            HistoryVO vo = new HistoryVO();
            vo.setTaskName(task.getName());
            vo.setStartTime(task.getStartTime().toString());
            // 结束时间和总耗时不能为 NUll
            if(task.getEndTime() != null && task.getDurationInMillis() != null){
                vo.setEndTime(task.getEndTime().toString());
                vo.setDurationInMillis(task.getDurationInMillis() / 1000 + "s");
                // 批注信息需要 taskService 来能获取到
                List<Comment> taskComments = taskService.getTaskComments(task.getId());
                if(taskComments != null && taskComments.size() > 0){
                    vo.setComment(taskComments.get(0).getFullMessage());
                }
            }
            return vo;
        }).collect(Collectors.toList());*/
        List<HistoryVO> historyVOList = new ArrayList<>();
        for (HistoricTaskInstance task : historicTaskInstanceList) {
            HistoryVO vo = new HistoryVO();
            vo.setTaskName(task.getName());
            vo.setStartTime(task.getStartTime());
            // 结束时间和总耗时不能为 NUll
            if(task.getEndTime() != null && task.getDurationInMillis() != null){
                vo.setEndTime(task.getEndTime());
                vo.setDurationInMillis(task.getDurationInMillis() / 1000 + "s");
                // 批注信息需要 taskService 来能获取到
                List<Comment> taskComments = taskService.getTaskComments(task.getId());
                if(taskComments != null && taskComments.size() > 0){
                    vo.setComment(taskComments.get(0).getFullMessage());
                }
            }
            historyVOList.add(vo);
        }
        return historyVOList;
    }

    /**
     * 查询代办任务列表
     */
    @Override
    public List<BusCarPackageAudit> todoTaskList(BusCarPackageAudit busCarPackageAudit) {
        //  1. 获取当前登录用户 ID
        Long userId = SecurityUtils.getUserId();
        // 	2. 获取 BpmnInfo 中的流程定义的 Key 和获取到的用户 ID 来查询待办任务列表 TaskList。
        // 获取 bpmnInfo 对象。我们固定是套餐
        BusBpmnInfo busBpmnInfo = busBpmnInfoService.selectByTypeId(BusCarPackageAudit.FLOW_AUDIT_TYPE);
        String processDefinitionKey = busBpmnInfo.getProcessDefinitionKey();
        // 根据 Key 和 负责人 来查询待办任务列表
        List<Task> taskList = taskService.createTaskQuery()
                .processDefinitionKey(processDefinitionKey)
                .taskAssignee(userId.toString())
                .list();
        if(taskList == null || taskList.size() == 0){
            // 没查询到任务
            return Collections.emptyList();
        }
        // 	3. 遍历这些任务 TaskList。获取到对应的流程实例 ID。
        // 遍历第一个版本（普通遍历）
        /*
        List<String> processInstanceIdList = new ArrayList<>();
        for (Task task : taskList) {
            processInstanceIdList.add(task.getProcessInstanceId());
        }
        */
        // 遍历第二个版本
        /*List<String> processInstanceIdList = taskList.stream().map(task -> {
            return task.getProcessInstanceId();
        }).collect(Collectors.toList());*/
        // 遍历第三个版本
        /*List<String> processInstanceIdList = taskList.stream().
                map(task -> task.getProcessInstanceId()).collect(Collectors.toList());*/
        // 遍历最终版
        List<String> processInstanceIdList = taskList.stream().
                map(Task::getProcessInstanceId).collect(Collectors.toList());
        // 	4. 根据流程实例 ID 就可以去我们快照表中查询到对应的信息。并展示到页面中。
        // 分页处理，因为上面的任务集合已经查询完了
        PageUtils.startPage();
        // 添加额外条件
        if(processInstanceIdList != null && processInstanceIdList.size() > 0){
            Map<String, Object> params = busCarPackageAudit.getParams();
            params.put("processInstanceIdList",processInstanceIdList);
        }
        List<BusCarPackageAudit> busCarPackageAudits = busCarPackageAuditMapper.selectBusCarPackageAuditList(busCarPackageAudit);
        return busCarPackageAudits;
    }

    /**
     * 审批功能
     */
    @Override
    @Transactional
    public void audit(AuditVO vo) {
        // 数据验证
        if(vo == null){
            throw new RuntimeException("非法参数");
        }
        if(vo.getId() == null || vo.getAuditStatus() == null){
            throw new RuntimeException("非法参数");
        }
        // 根据审批记录 id 查询审批状态   审核中才可以进行审批
        BusCarPackageAudit carPackageAudit = this.selectBusCarPackageAuditById(vo.getId());
        if(carPackageAudit == null){
            throw new RuntimeException("非法参数");
        }
        if(!BusCarPackageAudit.STATUS_IN_PROGRESS.equals(carPackageAudit.getStatus())){
            throw new RuntimeException("任务状态必须是审核中才可以进行审批操作");
        }
        // 获取到 carPackageAudit 中的 instanceId 。在根据当前用户 id。获取到当前任务
        String instanceId = carPackageAudit.getInstanceId();
        String userId = SecurityUtils.getUserId().toString();
        // 查询当前待办任务
        Task task = taskService.createTaskQuery()
                .processInstanceId(instanceId)
                .taskAssignee(userId)
                .singleResult();
        if(task == null){
            throw new RuntimeException("非法参数");
        }
        // 添加批注信息    审批意见：[xx:审批通过，批注信息:xxx]
        StringBuilder msg = new StringBuilder("审批意见:[");
        SysUser sysUser = userService.selectUserById(SecurityUtils.getUserId());
        msg.append(sysUser.getNickName()).append(":");
        // 将传递的审批意见转换为 boolean 类型。
        boolean auditStatus = BusCarPackageAudit.STATUS_PASS.equals(vo.getAuditStatus());
        if(auditStatus){
            // 审批通过
            msg.append("审批通过,批注信息:");
        } else {
            // 审批拒绝
            msg.append("审批拒绝,批注信息:");
        }
        msg.append(vo.getInfo()).append("]");
        // 为当前任务添加审批意见
        taskService.addComment(task.getId(),instanceId,msg.toString());
        // 设置流程变量 ${shopOwner} Key 必须与 bpmn 图上一致！！！ 同意或拒绝。更改流程后续走向
        Map<String,Object> params = new HashMap<>();
        params.put("shopOwner",auditStatus);
        // 若同意我们还需要设置一个 ${disCountPrice} Key 必须与 bpmn 图上一致！ 决定是否需要财务审批
        if(auditStatus){
            // 若直接设置可能不好使！ 因为 disCountPrice 是 BigDecimal 类型。Activiti7 不支持！
            // 若不好使我们则需要将其转换为 double 类型。然后流程定义。重新部署。
            params.put("disCountPrice",carPackageAudit.getServiceItemPrice().doubleValue());
        }
        // 完成任务
        taskService.complete(task.getId(),params);
        // 判断我们审批通过还是拒绝
        if(auditStatus){
            // 若审批通过
            // 查询是否还存在下一个任务。
            List<Task> nextTaskList = taskService.createTaskQuery()
                    .processInstanceId(instanceId)
                    .list();
            if(nextTaskList == null || nextTaskList.size() == 0){
                // 没有下一个任务了。说明该流程已经走完了。
                // 1. 将套餐审核列表（快照表） BusCarPackageAudit 状态 --> 审批通过
                busCarPackageAuditMapper.changeStatusById(carPackageAudit.getId(),BusCarPackageAudit.STATUS_PASS);
                // 2. 将其对应的服务项(业务表)  BusServiceItem 状态 --> 审批通过
                serviceItemService.changeAuditStatusById(carPackageAudit.getServiceItemId(),BusServiceItem.AUDITSTATUS_APPROVED);
            }
        } else {
            // 若审批拒绝
            // 1. 将套餐审核列表（快照表） BusCarPackageAudit 状态 --> 审批拒绝
            busCarPackageAuditMapper.changeStatusById(carPackageAudit.getId(),BusCarPackageAudit.STATUS_REJECT);
            // 2. 将其对应的服务项(业务表)  BusServiceItem 状态 --> 审批拒绝
            serviceItemService.changeAuditStatusById(carPackageAudit.getServiceItemId(),BusServiceItem.AUDITSTATUS_REPLY);
        }
    }

    /**
     * 查询已办任务列表
     */
    @Override
    @Transactional
    public List<BusCarPackageAudit> doneTaskList(BusCarPackageAudit busCarPackageAudit) {
        // 1. 获取当前登录用户
        Long userId = SecurityUtils.getUserId();
        // 2. 获取当前套餐的流程定义
        BusBpmnInfo busBpmnInfo = busBpmnInfoService.selectByTypeId(BusCarPackageAudit.FLOW_AUDIT_TYPE);
        if(busBpmnInfo == null){
            throw new RuntimeException("非法参数");
        }
        String processDefinitionKey = busBpmnInfo.getProcessDefinitionKey();
        // 3. 查询当前用户的历史任务集合
        List<HistoricTaskInstance> historyTaskList = historyService.createHistoricTaskInstanceQuery()
                .processDefinitionKey(processDefinitionKey)
                .taskAssignee(userId.toString())
                .finished() // 已完成任务
                .list();
        if(historyTaskList == null || historyTaskList.size() == 0){
            // 说明没有任何审批历史，就返回空集合
            return Collections.emptyList();
        }
        // 4. 遍历任务集合，拿到每个任务对应的流程实例 id
        List<String> processInstanceIdList = historyTaskList.stream()
                .map(HistoricTaskInstance::getProcessInstanceId).collect(Collectors.toList());
        // 5. 根据流程实例 id，去 CarPackageAudit（快照表） 中将数据查询出来返回
        if(processInstanceIdList == null || processInstanceIdList.size() == 0){
            throw new RuntimeException("非法参数");
        }
        // 将我们查询出来的流程实例 id 集合封装到当前对象参数的额外参数中
        busCarPackageAudit.getParams().put("processInstanceIdList",processInstanceIdList);
        // 分页
        PageUtils.startPage();
        // 根据流程实例 id 查询我们的套餐审核中的满足条件（已办）数据。
        return busCarPackageAuditMapper.selectBusCarPackageAuditList(busCarPackageAudit);
    }
}
